#include "httpsserver.hpp"
#include<string.h>
#include<thread>
HTTPSServer::~HTTPSServer(){
	delete root;
	for(unsigned int i=0,m=threadcount();i<m;i++){
		for(auto v:requests[i])delete v.second;
	}
	if(requests)delete[] requests;
}
bool HTTPSServer::openlib(){
	auto ret=SSLServer::openlib();
	return ret&openutil();
}
void HTTPSServer::closelib(){
	SSLServer::closelib();
	closeutil();
}
HTTPSServer::HTTPSServer(const char* rootpath,const std::string& compressmethod,
std::initializer_list<std::pair<std::string,MethodPair>> methods):
methods(methods.size()),root(new Dir(rootpath,"/",compressmethod)){
	for(auto& v:methods)this->methods.emplace(v.first,v.second);
	requests=nullptr;
}
bool HTTPSServer::Request::keep(){
	return value.containkeyvalue(keepalive,truestr);
}
HTTPSServer::Request::~Request(){
	for(auto v:responsebuffer)free(v);
}
void HTTPSServer::Request::reset(){
	versionlength=0;
	headcount=0;
	memset(keybuffer,0,LENTABLEKEY);
	memset(valuebuffer,0,LENTABLEVALUE);
	mode=ins_method;
	memset(version,0,LENVERSION);
	value.clear();
}
void HTTPSServer::Request::print(){
	char cache[LENVERSION+1];
	memcpy(cache,version,LENVERSION);
	cache[LENVERSION]=0;
	printf("user:%s\n",getip(info));
	printf("method:%p url:%s version:%s\n",method,url->name.c_str(),cache);
	for(auto& v:value)printf("%s:%s\n",v.first.c_str(),v.second.c_str());
	printf("data:%p(size:%zu) autofree:%d\n",memory.data,memory.size,memory.autofree);
}

size_t HTTPSServer::Request::datasize(){return memory.size;}
size_t HTTPSServer::Request::versionsize(){return versionlength;}
void HTTPSServer::Request::setdata(void* data,size_t size,bool autofree){
	memory=Memory{(char*)data,size,autofree};
}
static const std::string _0("0"),_t("Content-Length");
const StringTable HTTPSServer::defaulttable{{_t,_0}};
bool HTTPSServer::onhead(HTTPSServer* s,ThreadInfo* t,DataInfo* v,Request* r){
	static void* table[]={&&_ins_method,&&_ins_preurl,&&_ins_url,
	&&_ins_urlhex1,&&_ins_urlhex2,&&_ins_querykey,&&_ins_querykeyhex1,
	&&_ins_querykeyhex2,&&_ins_queryvalue,&&_ins_queryvaluehex1,
	&&_ins_queryvaluehex2,&&_ins_version,&&_ins_versionend,&&_ins_key,
	&&_ins_keyhex1,&&_ins_keyhex2,&&_ins_value,&&_ins_valuehex1,
	&&_ins_valuehex2,&&_ins_valueend,&&_ins_requestend,&&_ins_skip,
	&&_ins_skipend,&&_ins_skip2};
	static const std::string invalidrequest("请求错误");
	auto c=r->got;
	auto& method=s->methods;
	auto& m=r->value;
	Resource* res;
	MethodTable::iterator f;
	goto *table[r->mode];
	_ins_method:
	if(c!=' '){
		if(r->headcount<LENMETHODKEY){
			r->valuebuffer[r->headcount++]=c;
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	f=method.find(r->valuebuffer);
	if(f!=method.end()){
		r->method=&f->second;
		r->mode=Request::ins_preurl;
		memset(r->valuebuffer,0,r->headcount);
		r->headcount=0;
		r->url=s->root;
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_preurl:
	if(c=='/'){
		r->mode=Request::ins_url;
		return false;
	}
	_ins_url:
	if(c=='/'){
		auto p=r->url->get(r->valuebuffer);
		if(p){
			r->url=p;
			memset(r->valuebuffer,0,r->headcount);
			r->headcount=0;
			return false;
		}
		s->response(t,r,404,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c=='?'){
		res=r->url->get(r->valuebuffer);
		if(res){
			r->url=res;
			memset(r->valuebuffer,0,r->headcount);
			r->headcount=0;
			r->mode=Request::ins_querykey;
			return false;
		}
		s->response(t,r,404,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c=='%'){
		r->mode=Request::ins_urlhex1;
		return false;
	}
	if(c=='+'){
		if(r->headcount<LENRESOURCEKEY-1){
			r->valuebuffer[r->headcount++]=' ';
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c!=' '){
		if(r->headcount<LENRESOURCEKEY-1){
			r->valuebuffer[r->headcount++]=c;
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	res=r->url->get(r->valuebuffer);
	if(res){
		r->url=res;
		memset(r->valuebuffer,0,r->headcount);
		r->headcount=0;
		r->mode=Request::ins_version;
		return false;
	}
	s->response(t,r,404,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_urlhex1:
	if('0'<=c&&c<='9'){
		r->hex=(c-'0')<<4;
		r->mode=Request::ins_urlhex2;
		return false;
	}
	if('a'<=c&&c<='f'){
		r->hex=(c+(10-'a'))<<4;
		r->mode=Request::ins_urlhex2;
		return false;
	}
	if('A'<=c&&c<='F'){
		r->hex=(c+(10-'A'))<<4;
		r->mode=Request::ins_urlhex2;
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_urlhex2:
	if('0'<=c&&c<='9'){
		if(r->headcount<LENRESOURCEKEY-1){
			r->mode=Request::ins_url;
			r->valuebuffer[r->headcount++]=r->hex+(c-'0');
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('a'<=c&&c<='f'){
		if(r->headcount<LENRESOURCEKEY-1){
			r->mode=Request::ins_url;
			r->valuebuffer[r->headcount++]=r->hex+(c+(10-'a'));
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('A'<=c&&c<='F'){
		if(r->headcount<LENRESOURCEKEY-1){
			r->mode=Request::ins_url;
			r->valuebuffer[r->headcount++]=r->hex+(c+(10-'A'));
			return false;
		}
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_querykey:
	if(c==' '){
		s->response(t,r,401,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c=='%'){
		r->mode=Request::ins_querykeyhex1;
		return false;
	}
	if(c=='+'){
		if(r->headcount<LENTABLEKEY-1){
			r->keybuffer[r->headcount++]=' ';
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c!='='){
		if(r->headcount<LENTABLEKEY-1){
			r->keybuffer[r->headcount++]=c;
			return false;
		}
		s->response(t,r,401,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	r->mode=Request::ins_queryvalue;
	r->headcount=0;
	return false;
	_ins_querykeyhex1:
	if('0'<=c&&c<='9'){
		r->hex=(c-'0')<<4;
		r->mode=Request::ins_querykeyhex2;
		return false;
	}
	if('a'<=c&&c<='f'){
		r->hex=(c+(10-'a'))<<4;
		r->mode=Request::ins_querykeyhex2;
		return false;
	}
	if('A'<=c&&c<='F'){
		r->hex=(c+(10-'A'))<<4;
		r->mode=Request::ins_querykeyhex2;
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_querykeyhex2:
	if('0'<=c&&c<='9'){
		if(r->headcount<LENTABLEKEY-1){
			r->mode=Request::ins_querykey;
			r->keybuffer[r->headcount++]=r->hex+(c-'0');
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('a'<=c&&c<='f'){
		if(r->headcount<LENTABLEKEY-1){
			r->mode=Request::ins_querykey;
			r->keybuffer[r->headcount++]=r->hex+(c+(10-'a'));
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('A'<=c&&c<='F'){
		if(r->headcount<LENTABLEKEY-1){
			r->mode=Request::ins_querykey;
			r->keybuffer[r->headcount++]=r->hex+(c+(10-'A'));
			return false;
		}
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_queryvalue:
	if(c==' '){
		if(m.size()!=MAXKEYNUM){
			r->mode=Request::ins_version;
			r->value.emplace(r->keybuffer,r->valuebuffer);
			memset(r->keybuffer,0,LENTABLEKEY);
			memset(r->valuebuffer,0,r->headcount);
			r->headcount=0;
			return false;
		}
		s->response(t,r,401,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c=='%'){
		r->mode=Request::ins_queryvaluehex1;
		return false;
	}
	if(c=='+'){
		if(r->headcount<LENTABLEVALUE-1){
			r->valuebuffer[r->headcount++]=' ';
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c!='&'){
		if(r->headcount<LENTABLEVALUE-1){
			r->valuebuffer[r->headcount++]=c;
			return false;
		}
		s->response(t,r,401,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(m.size()!=MAXKEYNUM){
		r->mode=Request::ins_querykey;
		r->value.emplace(r->keybuffer,r->valuebuffer);
		memset(r->keybuffer,0,LENTABLEKEY);
		memset(r->valuebuffer,0,r->headcount);
		r->headcount=0;
		return false;
	}
	s->response(t,r,401,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_queryvaluehex1:
	if('0'<=c&&c<='9'){
		r->hex=(c-'0')<<4;
		r->mode=Request::ins_queryvaluehex2;
		return false;
	}
	if('a'<=c&&c<='f'){
		r->hex=(c+(10-'a'))<<4;
		r->mode=Request::ins_queryvaluehex2;
		return false;
	}
	if('A'<=c&&c<='F'){
		r->hex=(c+(10-'A'))<<4;
		r->mode=Request::ins_queryvaluehex2;
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_queryvaluehex2:
	if('0'<=c&&c<='9'){
		if(r->headcount<LENTABLEVALUE-1){
			r->mode=Request::ins_queryvalue;
			r->valuebuffer[r->headcount++]=r->hex+(c-'0');
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('a'<=c&&c<='f'){
		if(r->headcount<LENTABLEVALUE-1){
			r->mode=Request::ins_queryvalue;
			r->valuebuffer[r->headcount++]=r->hex+(c+(10-'a'));
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('A'<=c&&c<='F'){
		if(r->headcount<LENTABLEVALUE-1){
			r->mode=Request::ins_queryvalue;
			r->valuebuffer[r->headcount++]=r->hex+(c+(10-'A'));
			return false;
		}
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_version:
	if(c!='\r'){
		if(r->headcount<LENVERSION){
			r->version[r->headcount++]=c;
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	r->mode=Request::ins_versionend;
	return false;
	_ins_versionend:
	if(c=='\n'){
		r->versionlength=r->headcount;
		r->headcount=0;
		r->mode=r->method->skipvalue?Request::ins_skip2:Request::ins_key;
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_key:
	if(c=='\r'){
		r->mode=Request::ins_requestend;
		return false;
	}
	if(c=='%'){
		r->mode=Request::ins_keyhex1;
		return false;
	}
	if(c=='+'){
		if(r->headcount<LENTABLEKEY-1){
			r->keybuffer[r->headcount++]=' ';
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c!=':'){
		if(r->headcount<LENTABLEKEY-1){
			r->keybuffer[r->headcount++]=c;
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	r->mode=Request::ins_value;
	r->headcount=0;
	return false;
	_ins_keyhex1:
	if('0'<=c&&c<='9'){
		r->hex=(c-'0')<<4;
		r->mode=Request::ins_keyhex2;
		return false;
	}
	if('a'<=c&&c<='f'){
		r->hex=(c+(10-'a'))<<4;
		r->mode=Request::ins_keyhex2;
		return false;
	}
	if('A'<=c&&c<='F'){
		r->hex=(c+(10-'A'))<<4;
		r->mode=Request::ins_keyhex2;
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_keyhex2:
	if('0'<=c&&c<='9'){
		if(r->headcount<LENTABLEKEY-1){
			r->mode=Request::ins_key;
			r->keybuffer[r->headcount++]=r->hex+(c-'0');
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('a'<=c&&c<='f'){
		if(r->headcount<LENTABLEKEY-1){
			r->mode=Request::ins_key;
			r->keybuffer[r->headcount++]=r->hex+(c+(10-'a'));
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('A'<=c&&c<='F'){
		if(r->headcount<LENTABLEKEY-1){
			r->mode=Request::ins_key;
			r->keybuffer[r->headcount++]=r->hex+(c+(10-'A'));
			return false;
		}
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_value:
	if(c=='%'){
		r->mode=Request::ins_valuehex1;
		return false;
	}
	if(c=='+'){
		if(r->headcount<LENTABLEVALUE-1){
			r->valuebuffer[r->headcount++]=' ';
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if(c!='\r'){
		if(r->headcount<LENTABLEVALUE-1){
			r->valuebuffer[r->headcount++]=c;
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	r->mode=Request::ins_valueend;
	return false;
	_ins_valuehex1:
	if('0'<=c&&c<='9'){
		r->hex=(c-'0')<<4;
		r->mode=Request::ins_valuehex2;
		return false;
	}
	if('a'<=c&&c<='f'){
		r->hex=(c+(10-'a'))<<4;
		r->mode=Request::ins_valuehex2;
		return false;
	}
	if('A'<=c&&c<='F'){
		r->hex=(c+(10-'A'))<<4;
		r->mode=Request::ins_valuehex2;
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_valuehex2:
	if('0'<=c&&c<='9'){
		if(r->headcount<LENTABLEVALUE-1){
			r->mode=Request::ins_value;
			r->valuebuffer[r->headcount++]=r->hex+(c-'0');
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('a'<=c&&c<='f'){
		if(r->headcount<LENTABLEVALUE-1){
			r->mode=Request::ins_value;
			r->valuebuffer[r->headcount++]=r->hex+(c+(10-'a'));
			return false;
		}
		s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	if('A'<=c&&c<='F'){
		if(r->headcount<LENTABLEVALUE-1){
			r->mode=Request::ins_value;
			r->valuebuffer[r->headcount++]=r->hex+(c+(10-'A'));
			return false;
		}
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_valueend:
	if(c=='\n'){
		if(m.size()!=MAXKEYNUM){
			r->mode=Request::ins_key;
			r->value.emplace(r->keybuffer,r->valuebuffer);
			memset(r->keybuffer,0,LENTABLEKEY);
			memset(r->valuebuffer,0,r->headcount);
			r->headcount=0;
			return false;
		}
		s->response(t,r,402,invalidrequest,defaulttable,nullptr,0,false);
		return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_requestend:
	if(c=='\n'){
		auto ret=r->method->callback(s,t,r);
		if(ret){
			r->reset();
			return false;
		}
		return true;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_skip:if(c=='\r')r->mode=Request::ins_skipend;return false;
	_ins_skipend:
	if(c=='\n'){
		r->mode=Request::ins_skip2;return false;
	}
	s->response(t,r,400,invalidrequest,defaulttable,nullptr,0,false);
	return false;
	_ins_skip2:
	if(c=='\r'){
		r->mode=Request::ins_requestend;return false;
	}
	r->mode=Request::ins_skip;return false;
}

bool HTTPSServer::onmethod(HTTPSServer* s,ThreadInfo* t,DataInfo* v,void*){
	auto& m=s->requests[s->threadid(t)];
	auto f=m.find(v);
	if(f==m.end()){
		auto r=new Request();
		r->info=v;
		m.emplace(v,r);
		r->reset();
		r->setdata(nullptr,0,false);
		s->recvdata(t,v,{&r->got,1,(SSLServer::DataCallback)onhead,r});
	}
	return true;
}

void HTTPSServer::getdata(ThreadInfo* from,DataInfo* info,Request* request,
void* buffer,size_t size,bool autofree,MethodCallback callback){
	request->memory={(char*)buffer,size,autofree};
	recvdata(from,info,{(char*)buffer,size,(SSLServer::DataCallback)callback,request});
}

void HTTPSServer::response(ThreadInfo* from,Request* request,
unsigned int statuscode,const std::string& statustext,const StringTable& value,
void* data,size_t size,bool keep,DataCallback callback){
	auto info=request->info;
	std::string status(std::to_string(statuscode));
	auto vl=request->versionlength;
	auto sl=status.length();
	auto st=statustext.length();
	auto l=sl+st+vl+6;//两个空格两组\r\n
	for(auto& v:value)l+=v.first.length()+v.second.length()+3;//一个:一组\r\n
	auto buffer=(char*)malloc(l+sizeof(void*));
	*(DataCallback*)buffer=callback;
	if(buffer){
		request->responsebuffer.push_back(buffer);
		memcpy(buffer+sizeof(void*),request->version,vl);
		buffer[sizeof(void*)+vl]=' ';
		l=vl+(1+sizeof(void*));
		memcpy(buffer+l,status.c_str(),sl);
		l+=sl;
		buffer[l++]=' ';
		memcpy(buffer+l,statustext.c_str(),st);
		l+=st;
		buffer[l++]='\r';
		buffer[l++]='\n';
		for(auto& v:value){
			auto s=&v.first;
			vl=s->length();
			memcpy(buffer+l,s->c_str(),vl);
			l+=vl;
			buffer[l++]=':';
			s=&v.second;
			vl=s->length();
			memcpy(buffer+l,s->c_str(),vl);
			l+=vl;
			buffer[l++]='\r';
			buffer[l++]='\n';
		}
		buffer[l++]='\r';
		buffer[l++]='\n';
		if(keep){
			if(data){
				senddata(from,info,{buffer+sizeof(void*),l-sizeof(void*),SSLServer::emptysendback});
				senddata(from,info,{(char*)data,size,(SSLServer::DataCallback)onfinishdata,request});
				return;
			}
			senddata(from,info,{buffer+sizeof(void*),l-sizeof(void*),
			(SSLServer::DataCallback)onfinishdata,request});
			return;
		}
		//响应头结束
		if(data){
			senddata(from,info,{buffer+sizeof(void*),l-sizeof(void*),SSLServer::emptysendback});
			senddata(from,info,{(char*)data,size,ondatacloseclient,request});
			return;
		}
		senddata(from,info,{buffer+sizeof(void*),l-sizeof(void*),ondatacloseclient,request});
		return;
	}
	throw std::bad_alloc();
}

char* HTTPSServer::response(ThreadInfo* from,Request* request,unsigned int statuscode,
const std::string& statustext,const StringTable& value,size_t size,bool keep,DataCallback callback){
	auto info=request->info;
	std::string status(std::to_string(statuscode));
	auto vl=request->versionlength;
	auto sl=status.length();
	auto st=statustext.length();
	auto l=sl+st+vl+6;//两个空格两组\r\n
	for(auto& v:value)l+=v.first.length()+v.second.length()+3;//一个:一组\r\n
	auto buffer=(char*)malloc(l+sizeof(void*)+size);
	*(DataCallback*)buffer=callback;
	if(buffer){
		request->responsebuffer.push_back(buffer);
		memcpy(buffer+sizeof(void*),request->version,vl);
		buffer[sizeof(void*)+vl]=' ';
		l=vl+(1+sizeof(void*));
		memcpy(buffer+l,status.c_str(),sl);
		l+=sl;
		buffer[l++]=' ';
		memcpy(buffer+l,statustext.c_str(),st);
		l+=st;
		buffer[l++]='\r';
		buffer[l++]='\n';
		for(auto& v:value){
			auto s=&v.first;
			vl=s->length();
			memcpy(buffer+l,s->c_str(),vl);
			l+=vl;
			buffer[l++]=':';
			s=&v.second;
			vl=s->length();
			memcpy(buffer+l,s->c_str(),vl);
			l+=vl;
			buffer[l++]='\r';
			buffer[l++]='\n';
		}
		buffer[l++]='\r';
		buffer[l++]='\n';
		if(keep){
			senddata(from,info,{buffer+sizeof(void*),l+(size-sizeof(void*)),
			(SSLServer::DataCallback)onfinishdata,request});
			return buffer+l;
		}
		senddata(from,info,{buffer+sizeof(void*),l+(size-sizeof(void*)),ondatacloseclient,request});
		return buffer+l;
	}
	throw std::bad_alloc();
}

bool HTTPSServer::onfinishdata(HTTPSServer*s,ThreadInfo*t,DataInfo*,Request* r){
	auto p=r->responsebuffer.front();
	(*(DataCallback*)p)(s,t,r);
	free(p);
	r->responsebuffer.pop_front();
	return true;
}

bool HTTPSServer::ondatacloseclient(SSLServer* s,ThreadInfo* from,DataInfo* v,void* r){
	s->closeclient(from,v);
	return onfinishdata((HTTPSServer*)s,from,v,(Request*)r);
}

void HTTPSServer::oncloseclient(HTTPSServer* s,ThreadInfo* from,DataInfo* v,void* arg){
	auto& m=s->requests[s->threadid(from)];
	auto f=m.find(v);
	if(f!=m.end()){
		auto r=f->second;
		s->requestlost(s,from,r,arg);
		delete r;
		m.erase(f);
	}
}

int HTTPSServer::run(const char* keypath,const char* certpath,const char* address,unsigned int _port,RequestLostCallback onlost,
void* lostarg,unsigned int nthread,unsigned int maxpending,
time_t timeout,size_t maxconnect){
	if(requests){
		for(unsigned int i=0,m=threadcount();i<m;i++){
			for(auto v:requests[i])delete v.second;
		}
		if(requests)delete[] requests;
	}
	requests=new std::unordered_map<DataInfo*,Request*>[nthread==-1?std::thread::hardware_concurrency()-1:nthread-1]();
	requestlost=onlost;
	return SSLServer::run(keypath,certpath,address,_port,0,(SSLServer::DataCallback)onmethod,nullptr,
	(LostCallback)oncloseclient,lostarg,nthread,maxpending,timeout,maxconnect);
}

void HTTPSServer::emptyrequestlost(HTTPSServer*,ThreadInfo*,Request*,void*){}

bool HTTPSServer::sendfile(ThreadInfo* from,Request* request,
StringTable& value,File* file,bool keep){
	auto f=supportformat.find(file->extension);
	if(f!=supportformat.end()){
		auto& m=file->memory;
		std::string size(std::to_string(m.size));
		value.emplace(contenttype,f->second);
		value.emplace(contentlength,size);
		auto& method=file->compressmethod;
		if(method!="")value.emplace(contentencoding,method);
		if(keep)value.emplace(connection,lowerkeepalive);
		response(from,request,200,statusok,value,m.data,m.size,keep);
		return true;
	}
	return false;
}

bool HTTPSServer::sendfile(ThreadInfo* from,Request* request,File* file,bool keep){
	StringTable t;
	return sendfile(from,request,t,file,keep);
}
void HTTPSServer::update(){}
void HTTPSServer::emptysendback(HTTPSServer*,ThreadInfo*,Request*){}